package com.zy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zy.constant.AuthConstants;
import com.zy.constant.ManagerConstants;
import com.zy.domain.SysMenu;
import com.zy.domain.SysRoleMenu;
import com.zy.ex.handler.BusinessException;
import com.zy.mapper.SysRoleMenuMapper;
import com.zy.service.SysMenuService;
import com.zy.mapper.SysMenuMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
* @author RASH_ZY
* @description 针对表【sys_menu(菜单管理)】的数据库操作Service实现
* @createDate 2025-03-29 23:22:50
*/
@Service
@CacheConfig(cacheNames = "com.zy.service.impl.SysMenuServiceImpl") //使用注解缓存的类
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu>
    implements SysMenuService{

    @Autowired
    private SysMenuMapper sysMenuMapper;

    @Autowired
    private SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * 查询用户菜单权限集合
     * 通过注解缓存写入Redis(一个人的角色短时间内是不变的，权限也就不变，存储到缓存当中，避免每次登录都查询数据库)
     * @param loginUserId
     * @return
     */
    @Override
    @Cacheable(key = "#loginUserId") //该方法查询数据添加到Redis缓存中
    public Set<SysMenu> queryUserMenuListByUserId(Long loginUserId) {
        //根据用户id查询用户菜单权限集合
        Set<SysMenu> menus = sysMenuMapper.selectUserMenuListByUserId(loginUserId);
        //将菜单权限集合转换为树结构(层级关系，子菜单)
        return transformTree(menus, 0L);
    }

    /**
     * 集合转换为树结构，两种情况
     * 1.已知菜单深度 <=2
     *
     * 2.未知菜单深度
     * @param menus
     * @param pid
     * @return
     */
    private Set<SysMenu> transformTree(Set<SysMenu> menus, long pid) {
        /**
         * 已知菜单深度 <=2
         */
        /*//从菜单权限集合中获取根节点集合
        Set<SysMenu> roots = menus.stream()
                .filter(m -> m.getParentId().equals(pid)) //m为当前节点，pid默认值为0，即根节点
                .collect(Collectors.toSet());
        //遍历根节点集合
        roots.forEach(root -> {
            //从菜单集合中过滤出他的父节点值与当前根节点id值一致的菜单集合
            Set<SysMenu> child = menus.stream()
                    .filter( m -> m.getParentId().equals(root.getMenuId()))
                    .collect(Collectors.toSet());
            root.setChildList(child);
        });*/

        /**
         * 未知菜单深度 递归
         */
        //从菜单权限集合中获取根节点集合
        Set<SysMenu> roots = menus.stream()
                .filter(m -> m.getParentId().equals(pid)) //m为当前节点，pid默认值为0，即根节点
                .collect(Collectors.toSet());
        //遍历根节点集合，将其子节点存入childList，子节点由需要遍历其子节点(递归实现，传入菜单集合+当前节点id)
        roots.forEach( r -> r.setList(transformTree(menus, r.getMenuId()))); //菜单集合+当前节点id(即子节点父id)
        return roots;
    }

    /**
     * 查询系统所有权限集合：菜单+操作
     * @return
     */
    @Override
    @Cacheable(key = ManagerConstants.SYS_ALL_MENU_KEY)
    public List<SysMenu> queryAllSysMenuList() {
        return sysMenuMapper.selectList(null);
    }

    /**
     * 新增权限，需要删除权限缓存
     * @param sysMenu
     * @return
     */
    @Override
    @CacheEvict(key = ManagerConstants.SYS_ALL_MENU_KEY)
    public Boolean saveSysMenu(SysMenu sysMenu) {
        return sysMenuMapper.insert(sysMenu) > 0;
    }

    /**
     * 修改权限信息，需要删除权限缓存
     * @param sysMenu
     * @return
     */
    @Override
    @CacheEvict(key = ManagerConstants.SYS_ALL_MENU_KEY)
    public boolean modifySysMenu(SysMenu sysMenu) {
        //获取菜单类型
        Integer type = sysMenu.getType();
        if (type==0) {
            //type为0，则代表其为目录，设置其上级目录id为0(parentId=0)
            sysMenu.setParentId(0L);
        }
        return (sysMenuMapper.updateById(sysMenu) > 0);
    }

    /**
     * 删除权限，需要删除权限缓存、角色缓存
     *  1.删除角色权限关系
     *  2.删除权限
     * @param menuId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @Caching(evict = {
        @CacheEvict(key = ManagerConstants.SYS_ALL_MENU_KEY),
        @CacheEvict(key = ManagerConstants.SYS_ALL_ROLE_KEY)
    })
    public Boolean removeSysMenuById(Long menuId) {
        //获取当前菜单权限的子节点集合
        List<SysMenu> childMenuList = sysMenuMapper.selectList(new LambdaQueryWrapper<SysMenu>()
                .eq(SysMenu::getParentId, menuId)
        );
        //子菜单集合有元素，不可删除
        if (CollectionUtil.isNotEmpty(childMenuList) && childMenuList.size() != 0) {
            throw new BusinessException("当前菜单包含子菜单，不可删除");
        }
        //子菜单集合为空，可以删除
        //1.先删除角色权限关系
        //获取角色权限关系集合
        List<SysRoleMenu> sysRoleMenuList = sysRoleMenuMapper.selectList(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getMenuId, menuId));
        boolean deleteRoleMenu = sysRoleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>()
                .eq(SysRoleMenu::getMenuId, menuId)
        ) == sysRoleMenuList.size();
        //2.再删除权限
        boolean deleteMenu = sysMenuMapper.deleteById(menuId) > 0;
        return (deleteMenu && deleteRoleMenu);
    }
}




